home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 1: Comms & Networking / Almathera Ten on Ten - Disc 1: Comms & Networking.iso / amiga-useful / perl / src / form.c < prev    next >
C/C++ Source or Header  |  1995-05-04  |  9KB  |  398 lines

  1. /* $RCSfile: form.c,v $$Revision: 4.0.1.3 $$Date: 92/06/08 13:21:42 $
  2.  *
  3.  *    Copyright (c) 1991, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of either the GNU General Public
  6.  *    License or the Artistic License, as specified in the README file.
  7.  *
  8.  * $Log:    form.c,v $
  9.  * Revision 4.0.1.3  92/06/08  13:21:42  lwall
  10.  * patch20: removed implicit int declarations on funcions
  11.  * patch20: form feed for formats is now specifiable via $^L
  12.  * patch20: Perl now distinguishes overlapped copies from non-overlapped
  13.  * 
  14.  * Revision 4.0.1.2  91/11/05  17:18:43  lwall
  15.  * patch11: formats didn't fill their fields as well as they could
  16.  * patch11: ^ fields chopped hyphens on line break
  17.  * patch11: # fields could write outside allocated memory
  18.  * 
  19.  * Revision 4.0.1.1  91/06/07  11:07:59  lwall
  20.  * patch4: new copyright notice
  21.  * patch4: default top-of-form format is now FILEHANDLE_TOP
  22.  * 
  23.  * Revision 4.0  91/03/20  01:19:23  lwall
  24.  * 4.0 baseline.
  25.  * 
  26.  */
  27.  
  28. #include "EXTERN.h"
  29. #include "perl.h"
  30.  
  31. /* Forms stuff */
  32.  
  33. static int countlines();
  34.  
  35. void
  36. form_parseargs(fcmd)
  37. register FCMD *fcmd;
  38. {
  39.     register int i;
  40.     register ARG *arg;
  41.     register int items;
  42.     STR *str;
  43.     ARG *parselist();
  44.     line_t oldline = curcmd->c_line;
  45.     int oldsave = savestack->ary_fill;
  46.  
  47.     str = fcmd->f_unparsed;
  48.     curcmd->c_line = fcmd->f_line;
  49.     fcmd->f_unparsed = Nullstr;
  50.     (void)savehptr(&curstash);
  51.     curstash = str->str_u.str_hash;
  52.     arg = parselist(str);
  53.     restorelist(oldsave);
  54.  
  55.     items = arg->arg_len - 1;    /* ignore $$ on end */
  56.     for (i = 1; i <= items; i++) {
  57.     if (!fcmd || fcmd->f_type == F_NULL)
  58.         fatal("Too many field values");
  59.     dehoist(arg,i);
  60.     fcmd->f_expr = make_op(O_ITEM,1,
  61.       arg[i].arg_ptr.arg_arg,Nullarg,Nullarg);
  62.     if (fcmd->f_flags & FC_CHOP) {
  63.         if ((fcmd->f_expr[1].arg_type & A_MASK) == A_STAB)
  64.         fcmd->f_expr[1].arg_type = A_LVAL;
  65.         else if ((fcmd->f_expr[1].arg_type & A_MASK) == A_EXPR)
  66.         fcmd->f_expr[1].arg_type = A_LEXPR;
  67.         else
  68.         fatal("^ field requires scalar lvalue");
  69.     }
  70.     fcmd = fcmd->f_next;
  71.     }
  72.     if (fcmd && fcmd->f_type)
  73.     fatal("Not enough field values");
  74.     curcmd->c_line = oldline;
  75.     Safefree(arg);
  76.     str_free(str);
  77. }
  78.  
  79. int newsize;
  80.  
  81. #define CHKLEN(allow) \
  82. newsize = (d - orec->o_str) + (allow); \
  83. if (newsize >= curlen) { \
  84.     curlen = d - orec->o_str; \
  85.     GROWSTR(&orec->o_str,&orec->o_len,orec->o_len + (allow)); \
  86.     d = orec->o_str + curlen;    /* in case it moves */ \
  87.     curlen = orec->o_len - 2; \
  88. }
  89.  
  90. void
  91. format(orec,fcmd,sp)
  92. register struct outrec *orec;
  93. register FCMD *fcmd;
  94. int sp;
  95. {
  96.     register char *d = orec->o_str;
  97.     register char *s;
  98.     register int curlen = orec->o_len - 2;
  99.     register int size;
  100.     FCMD *nextfcmd;
  101.     FCMD *linebeg = fcmd;
  102.     char tmpchar;
  103.     char *t;
  104.     CMD mycmd;
  105.     STR *str;
  106.     char *chophere;
  107.  
  108.     mycmd.c_type = C_NULL;
  109.     orec->o_lines = 0;
  110.     for (; fcmd; fcmd = nextfcmd) {
  111.     nextfcmd = fcmd->f_next;
  112.     CHKLEN(fcmd->f_presize);
  113.     /*SUPPRESS 560*/
  114.     if (s = fcmd->f_pre) {
  115.         while (*s) {
  116.         if (*s == '\n') {
  117.             while (d > orec->o_str && (d[-1] == ' ' || d[-1] == '\t'))
  118.             d--;
  119.             if (fcmd->f_flags & FC_NOBLANK) {
  120.             if (d == orec->o_str || d[-1] == '\n') {
  121.                 orec->o_lines--;    /* don't print blank line */
  122.                 linebeg = fcmd->f_next;
  123.                 break;
  124.             }
  125.             else if (fcmd->f_flags & FC_REPEAT)
  126.                 nextfcmd = linebeg;
  127.             else
  128.                 linebeg = fcmd->f_next;
  129.             }
  130.             else
  131.             linebeg = fcmd->f_next;
  132.         }
  133.         *d++ = *s++;
  134.         }
  135.     }
  136.     if (fcmd->f_unparsed)
  137.         form_parseargs(fcmd);
  138.     switch (fcmd->f_type) {
  139.     case F_NULL:
  140.         orec->o_lines++;
  141.         break;
  142.     case F_LEFT:
  143.         (void)eval(fcmd->f_expr,G_SCALAR,sp);
  144.         str = stack->ary_array[sp+1];
  145.         s = str_get(str);
  146.         size = fcmd->f_size;
  147.         CHKLEN(size);
  148.         chophere = Nullch;
  149.         while (size && *s && *s != '\n') {
  150.         if (*s == '\t')
  151.             *s = ' ';
  152.         size--;
  153.         if (*s && index(chopset,(*d++ = *s++)))
  154.             chophere = s;
  155.         if (*s == '\n' && (fcmd->f_flags & FC_CHOP))
  156.             *s = ' ';
  157.         }
  158.         if (size || !*s)
  159.         chophere = s;
  160.         else if (chophere && chophere < s && *s && index(chopset,*s))
  161.         chophere = s;
  162.         if (fcmd->f_flags & FC_CHOP) {
  163.         if (!chophere)
  164.             chophere = s;
  165.         size += (s - chophere);
  166.         d -= (s - chophere);
  167.         if (fcmd->f_flags & FC_MORE &&
  168.           *chophere && strNE(chophere,"\n")) {
  169.             while (size < 3) {
  170.             d--;
  171.             size++;
  172.             }
  173.             while (d[-1] == ' ' && size < fcmd->f_size) {
  174.             d--;
  175.             size++;
  176.             }
  177.             *d++ = '.';
  178.             *d++ = '.';
  179.             *d++ = '.';
  180.             size -= 3;
  181.         }
  182.         while (*chophere && index(chopset,*chophere)
  183.           && isSPACE(*chophere))
  184.             chophere++;
  185.         str_chop(str,chophere);
  186.         }
  187.         if (fcmd->f_next && fcmd->f_next->f_pre[0] == '\n')
  188.         size = 0;            /* no spaces before newline */
  189.         while (size) {
  190.         size--;
  191.         *d++ = ' ';
  192.         }
  193.         break;
  194.     case F_RIGHT:
  195.         (void)eval(fcmd->f_expr,G_SCALAR,sp);
  196.         str = stack->ary_array[sp+1];
  197.         t = s = str_get(str);
  198.         size = fcmd->f_size;
  199.         CHKLEN(size);
  200.         chophere = Nullch;
  201.         while (size && *s && *s != '\n') {
  202.         if (*s == '\t')
  203.             *s = ' ';
  204.         size--;
  205.         if (*s && index(chopset,*s++))
  206.             chophere = s;
  207.         if (*s == '\n' && (fcmd->f_flags & FC_CHOP))
  208.             *s = ' ';
  209.         }
  210.         if (size || !*s)
  211.         chophere = s;
  212.         else if (chophere && chophere < s && *s && index(chopset,*s))
  213.         chophere = s;
  214.         if (fcmd->f_flags & FC_CHOP) {
  215.         if (!chophere)
  216.             chophere = s;
  217.         size += (s - chophere);
  218.         s = chophere;
  219.         while (*chophere && index(chopset,*chophere)
  220.           && isSPACE(*chophere))
  221.             chophere++;
  222.         }
  223.         tmpchar = *s;
  224.         *s = '\0';
  225.         while (size) {
  226.         size--;
  227.         *d++ = ' ';
  228.         }
  229.         size = s - t;
  230.         Copy(t,d,size,char);
  231.         d += size;
  232.         *s = tmpchar;
  233.         if (fcmd->f_flags & FC_CHOP)
  234.         str_chop(str,chophere);
  235.         break;
  236.     case F_CENTER: {
  237.         int halfsize;
  238.  
  239.         (void)eval(fcmd->f_expr,G_SCALAR,sp);
  240.         str = stack->ary_array[sp+1];
  241.         t = s = str_get(str);
  242.         size = fcmd->f_size;
  243.         CHKLEN(size);
  244.         chophere = Nullch;
  245.         while (size && *s && *s != '\n') {
  246.         if (*s == '\t')
  247.             *s = ' ';
  248.         size--;
  249.         if (*s && index(chopset,*s++))
  250.             chophere = s;
  251.         if (*s == '\n' && (fcmd->f_flags & FC_CHOP))
  252.             *s = ' ';
  253.         }
  254.         if (size || !*s)
  255.         chophere = s;
  256.         else if (chophere && chophere < s && *s && index(chopset,*s))
  257.         chophere = s;
  258.         if (fcmd->f_flags & FC_CHOP) {
  259.         if (!chophere)
  260.             chophere = s;
  261.         size += (s - chophere);
  262.         s = chophere;
  263.         while (*chophere && index(chopset,*chophere)
  264.           && isSPACE(*chophere))
  265.             chophere++;
  266.         }
  267.         tmpchar = *s;
  268.         *s = '\0';
  269.         halfsize = size / 2;
  270.         while (size > halfsize) {
  271.         size--;
  272.         *d++ = ' ';
  273.         }
  274.         size = s - t;
  275.         Copy(t,d,size,char);
  276.         d += size;
  277.         *s = tmpchar;
  278.         if (fcmd->f_next && fcmd->f_next->f_pre[0] == '\n')
  279.         size = 0;            /* no spaces before newline */
  280.         else
  281.         size = halfsize;
  282.         while (size) {
  283.         size--;
  284.         *d++ = ' ';
  285.         }
  286.         if (fcmd->f_flags & FC_CHOP)
  287.         str_chop(str,chophere);
  288.         break;
  289.     }
  290.     case F_LINES:
  291.         (void)eval(fcmd->f_expr,G_SCALAR,sp);
  292.         str = stack->ary_array[sp+1];
  293.         s = str_get(str);
  294.         size = str_len(str);
  295.         CHKLEN(size+1);
  296.         orec->o_lines += countlines(s,size) - 1;
  297.         Copy(s,d,size,char);
  298.         d += size;
  299.         if (size && s[size-1] != '\n') {
  300.         *d++ = '\n';
  301.         orec->o_lines++;
  302.         }
  303.         linebeg = fcmd->f_next;
  304.         break;
  305.     case F_DECIMAL: {
  306.         double value;
  307.  
  308.         (void)eval(fcmd->f_expr,G_SCALAR,sp);
  309.         str = stack->ary_array[sp+1];
  310.         size = fcmd->f_size;
  311.         CHKLEN(size+1);
  312.         /* If the field is marked with ^ and the value is undefined,
  313.            blank it out. */
  314.         if ((fcmd->f_flags & FC_CHOP) && !str->str_pok && !str->str_nok) {
  315.         while (size) {
  316.             size--;
  317.             *d++ = ' ';
  318.         }
  319.         break;
  320.         }
  321.         value = str_gnum(str);
  322.         if (fcmd->f_flags & FC_DP) {
  323.         sprintf(d, "%#*.*f", size, fcmd->f_decimals, value);
  324.         } else {
  325.         sprintf(d, "%*.0f", size, value);
  326.         }
  327.         d += size;
  328.         break;
  329.     }
  330.     }
  331.     }
  332.     CHKLEN(1);
  333.     *d++ = '\0';
  334. }
  335.  
  336. static int
  337. countlines(s,size)
  338. register char *s;
  339. register int size;
  340. {
  341.     register int count = 0;
  342.  
  343.     while (size--) {
  344.     if (*s++ == '\n')
  345.         count++;
  346.     }
  347.     return count;
  348. }
  349.  
  350. void
  351. do_write(orec,stab,sp)
  352. struct outrec *orec;
  353. STAB *stab;
  354. int sp;
  355. {
  356.     register STIO *stio = stab_io(stab);
  357.     FILE *ofp = stio->ofp;
  358.  
  359. #ifdef DEBUGGING
  360.     if (debug & 256)
  361.     fprintf(stderr,"left=%ld, todo=%ld\n",
  362.       (long)stio->lines_left, (long)orec->o_lines);
  363. #endif
  364.     if (stio->lines_left < orec->o_lines) {
  365.     if (!stio->top_stab) {
  366.         STAB *topstab;
  367.         char tmpbuf[256];
  368.  
  369.         if (!stio->top_name) {
  370.         if (!stio->fmt_name)
  371.             stio->fmt_name = savestr(stab_name(stab));
  372.         sprintf(tmpbuf, "%s_TOP", stio->fmt_name);
  373.         topstab = stabent(tmpbuf,FALSE);
  374.         if (topstab && stab_form(topstab))
  375.             stio->top_name = savestr(tmpbuf);
  376.         else
  377.             stio->top_name = savestr("top");
  378.         }
  379.         topstab = stabent(stio->top_name,FALSE);
  380.         if (!topstab || !stab_form(topstab)) {
  381.         stio->lines_left = 100000000;
  382.         goto forget_top;
  383.         }
  384.         stio->top_stab = topstab;
  385.     }
  386.     if (stio->lines_left >= 0 && stio->page > 0)
  387.         fwrite(formfeed->str_ptr, formfeed->str_cur, 1, ofp);
  388.     stio->lines_left = stio->page_len;
  389.     stio->page++;
  390.     format(&toprec,stab_form(stio->top_stab),sp);
  391.     fputs(toprec.o_str,ofp);
  392.     stio->lines_left -= toprec.o_lines;
  393.     }
  394.   forget_top:
  395.     fputs(orec->o_str,ofp);
  396.     stio->lines_left -= orec->o_lines;
  397. }
  398.